using System;
#if (SILVERLIGHT)
using System.IO;
#endif
using ValidationFramework.Configuration;
using ValidationFramework.Configuration.Reflection;

namespace ValidationFramework.Specifications 
{
    /// <summary>
    /// Specifies that a <see cref="InlineSpecification"/> should be applied to the program element.
    /// </summary>
    /// <seealso cref="CustomRule"/>
    /// <seealso cref="CustomRuleConfigReader"/>
    /// <seealso cref="CustomValidationEventArgs"/>
    /// <example>
    /// <code source="Examples\ExampleLibraryCSharp\Specifications\CustomRuleAttributeExample.cs" lang="cs"/>
    /// <code source="Examples\ExampleLibraryVB\Specifications\CustomRuleAttributeExample.vb" lang="vbnet"/>
    /// </example>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Field, AllowMultiple = true, Inherited = true)]

#if (!SILVERLIGHT)
    [Serializable]
#endif
	public sealed class SatisfiesDelegateAttribute: RuleAttribute
    {

        // --- Constructors

        /// <param name="validationTypeName">The name of the <see cref="Type"/> that the <see cref="ValidationMethod"/> exists on.</param>
        /// <param name="validationMethod">The name of the method to use when running <see cref="Rule.Validate"/>.</param>
        /// <param name="ruleInterpretation">The business interpretation of the <see cref="CustomRuleAttribute"/>.</param>
        /// <exception cref="ArgumentNullException"><paramref name="ruleInterpretation"/> is a null reference.</exception>
        /// <exception cref="ArgumentException"><paramref name="ruleInterpretation"/> is <see cref="string.Empty"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="validationTypeName"/> is a null reference.</exception>
        /// <exception cref="ArgumentException"><paramref name="validationTypeName"/> is <see cref="string.Empty"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="validationMethod"/> is a null reference.</exception>
        /// <exception cref="ArgumentException"><paramref name="validationMethod"/> is <see cref="string.Empty"/>.</exception>
        public SatisfiesDelegateAttribute(string validationTypeName, string validationMethod, string ruleInterpretation)
        {
        	Guard.ArgumentNotNullOrEmptyString(validationTypeName, "validationTypeName");
        	Guard.ArgumentNotNullOrEmptyString(validationMethod, "validationMethod");
        	Guard.ArgumentNotNullOrEmptyString(ruleInterpretation, "ruleInterpretation");
        	
			ValidationTypeName = validationTypeName;
			ValidationMethodName = validationMethod;
			Interpretation = ruleInterpretation;
        }


		// --- Properties

        /// <summary>
        /// Gets the name of the method to use when running <see cref="Rule.Validate"/>.
        /// </summary>
		public string ValidationMethodName
		{
			get; 
			private set;
		}

        /// <summary>
        /// Gets a <see cref="string"/> that is a business interpretation of the <see cref="Rule"/>.
        /// </summary>
        /// <remarks>
        /// Used as a helper to document the API that <see cref="Rule"/>s area applied to.
        /// </remarks>
        public string Interpretation
        {
			get;
			private set;
        }

        /// <summary>
        /// Gets the name of the <see cref="Type"/> that the <see cref="ValidationMethod"/> exists on.
        /// </summary>
        public string ValidationTypeName
        {
			get;
			private set;
        }


		// --- RuleAttribute overrides
		public override ISpecification CreateSpecification(ICachedReflectionInfo descriptor)
		{
			var method = SatisfiesDelegateSpec.ResolveValidateMethod(ValidationTypeName, ValidationMethodName);
			return new SatisfiesDelegateSpec(method, Interpretation);
		}

	}
}